﻿using System;
using System.Collections.Generic;
using Sharp3DMath.Geometry2D;
using System.Drawing;
using Sharp3DMath.Strokes;
using System.Drawing.Drawing2D;
using System.Text;

namespace Sharp3DMath.Core
{
    public static class GraphicsEx
    {
        public static void DrawLines(Graphics graphics, Pen pen, Vector2F[] points)
        {
            PointF[] pts = new PointF[points.Length];
            for (int i = 0; i < points.Length; i++)
            {
                pts[i] = points[i].ToPointF();
            }
            graphics.DrawLines(pen, pts);
        }
        public static void DrawStroke(Graphics graphics,Pen pen,Stroke stroke)
        {
            DrawLines(graphics, pen, stroke.Points);
        }
        public static void DrawBeautyStroke(Graphics graphics,Pen beautyPen,Stroke stroke,SharpType type)
        {
            switch (type)
            {
                case SharpType.Line:
                    GraphicsEx.DrawLine(graphics,beautyPen, stroke.Points[0], stroke.Points[1]);

                    break;
                case SharpType.Triangle:
                    GraphicsEx.DrawPolygon(graphics, beautyPen, stroke.Points.ToArray());
                    break;
                case SharpType.Rectangle:
                    GraphicsEx.DrawPolygon(graphics, beautyPen, stroke.Points.ToArray());
                    break;
                case SharpType.Circles:
                    GraphicsEx.DrawRotateEllipse(graphics, beautyPen, stroke.Points.ToArray());
                    break;
                case SharpType.Ellipse:
                    GraphicsEx.DrawRotateEllipse(graphics, beautyPen, stroke.Points.ToArray());
                    break;
                case SharpType.Diamond:
                    GraphicsEx.DrawPolygon(graphics, beautyPen, stroke.Points.ToArray());
                    break;
                case SharpType.Trapezia:
                    GraphicsEx.DrawPolygon(graphics, beautyPen, stroke.Points.ToArray());
                    break;
                case SharpType.FoldLine:
                    GraphicsEx.DrawStroke(graphics, beautyPen, stroke);
                    break;
                case SharpType.Spiral:
                    GraphicsEx.DrawBSpline(graphics, beautyPen, MathEx.BezierSpline.GetBezierSplinePoints(stroke.Points.ToArray()));
                    GraphicsEx.DrawVertexs(graphics, new Pen(Color.Red,1), stroke.Points.ToArray());
                    break;
                case SharpType.ConcentricHelix:
                    GraphicsEx.DrawStroke(graphics, beautyPen, stroke);
                    break;
                case SharpType.Curve:
                    GraphicsEx.DrawBSpline(graphics, beautyPen, MathEx.BezierSpline.GetBezierSplinePoints(stroke.Points.ToArray()));
                    GraphicsEx.DrawVertexs(graphics, new Pen(Color.Red, 1), stroke.Points.ToArray());
                    break;
                case SharpType.Arc:
                    GraphicsEx.DrawLines(graphics, beautyPen, stroke.Points.ToArray());
                    break;
                case SharpType.Delete:
                    GraphicsEx.DrawStroke(graphics, beautyPen, stroke);
                    break;
                case SharpType.Pentacle:
                    GraphicsEx.DrawStroke(graphics, beautyPen, stroke);
                    break;
                case SharpType.Last:
                    break;
                default:
                    break;
            }
        }
        public static void DrawLines(Graphics graphics, Pen pen, List<Vector2F> points)
        {
            if (points.Count < 2)
            {
                return;
            }
            PointF[] pts = new PointF[points.Count];
            for (int i = 0; i < points.Count; i++)
            {
                pts[i] = points[i].ToPointF();
            }
            graphics.DrawLines(pen, pts);
        }
        public static void DrawLines(Graphics graphics, Pen pen,Vector2F[] points,int s,int e)
        {
            PointF[] pts = new PointF[e-s+1];
            for (int i = s; i <=e; i++)
            {
                pts[i-s] = points[i].ToPointF();
            }
            graphics.DrawLines(pen, pts);
        }

        public static void DrawVertex(Graphics graphics,Pen pen,Vector2F vertex)
        {
            RectangleF rect = new RectangleF(vertex.X, vertex.Y, 0, 0);
            rect.Inflate(3, 3);
            graphics.DrawRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height);
        }
        public static void DrawVertexs(Graphics graphics, Pen pen, Vector2F[] vertexs)
        {
            foreach (var item in vertexs)
            {
                DrawVertex(graphics, pen, item);
            }
        }
        public static void DrawLine(Graphics graphics, Pen pen, Vector2F p1, Vector2F p2)
        {
            graphics.DrawLine(pen, p1.ToPointF(), p2.ToPointF());
        }

        public static void DrawString(Graphics graphics, String s, Font font, Brush brush, Vector2F point)
        {
            graphics.DrawString(s, font, brush, point.ToPointF());
        }
        public static void DrawPolygon(Graphics graphics, Pen pen, Vector2F[] vertex)
        {
            if (vertex.Length < 2)
            {
                return;
            }
            PointF[] points = Vector2F.ToPointFArray(vertex);
            graphics.DrawPolygon(pen, points);
        }
        public static void DrawTriangle(Graphics graphics, Pen pen, Vector2F A, Vector2F B, Vector2F C)
        {

        }
        public static void DrawQuadrilateral(Graphics graphics, Pen pen)
        {

        }
        public static void DrawEllipse(Graphics graphics, Pen pen, Vector2F[] boundBox)
        {

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="pen"></param>
        /// <param name="boundBox">four points,boundBox</param>
        public static void DrawRotateEllipse(Graphics graphics, Pen pen, Vector2F[] boundBox)
        {
            Vector2F fPoint = boundBox[0];
            Vector2F sPoint = boundBox[1];
            Vector2F tPoint = boundBox[2];
            float width = DistanceMethods.Distance(fPoint, sPoint);
            float height = DistanceMethods.Distance(sPoint, tPoint);
            Vector2F initVect = fPoint - sPoint;
            float m11, m12, m21, m22, length;
            length = initVect.GetLength();

            m11 = initVect.X / length;
            m12 = initVect.Y / length;
            m21 = -initVect.Y / length;
            m22 = initVect.X / length;

            Matrix matrix = new Matrix(m11, m12, m21, m22, sPoint.X, sPoint.Y);
            

            Matrix oldmatrix = graphics.Transform;
            graphics.Transform = matrix;
            graphics.DrawEllipse(pen, new RectangleF(0, -height, width, height));
            

            graphics.Transform = oldmatrix;

        }
        /// <summary>
        /// Draw Bezier - Spline
        /// [knot,control1,control2,knot,control1,control2,knot,control1...knot]
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="pen"></param>
        /// <param name="points">Bezier Spline Points</param>
        /// <returns></returns>
        public static void DrawBSpline(Graphics graphics,Pen pen,Vector2F[] bezierSplinePoints)
        {
            PointF[] pts = new PointF[bezierSplinePoints.Length];
            for (int i = 0; i < bezierSplinePoints.Length; i++)
            {
                pts[i] = bezierSplinePoints[i].ToPointF();
            }
            graphics.DrawBeziers(pen, pts);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="pen"></param>
        /// <param name="boundBox"></param>
        /// <param name="startPoint"></param>
        /// <param name="endPoint"></param>
        public static void DrawRotateArc(Graphics graphics,Pen pen,Vector2F[] boundBox,Vector2F startPoint,Vector2F endPoint,bool direction)
        {
            //Todo 传入坐标

            Vector2F fPoint = boundBox[0];
            Vector2F sPoint = boundBox[1];
            Vector2F tPoint = boundBox[2];
            float width = DistanceMethods.Distance(fPoint, sPoint);
            float height = DistanceMethods.Distance(sPoint, tPoint);
            Vector2F initVect = fPoint - sPoint;
            float m11, m12, m21, m22, length;
            length = initVect.GetLength();

            m11 = initVect.X / length;
            m12 = initVect.Y / length;
            m21 = -initVect.Y / length;
            m22 = initVect.X / length;

            Matrix matrix = new Matrix(m11, m12, m21, m22, sPoint.X, sPoint.Y);
            

            Matrix matrix2 = new Matrix(m11,m12,m21,m22,sPoint.X,sPoint.Y);
            matrix2.Invert();
            PointF[] sepoints = new PointF[3];
            sepoints[0] = startPoint.ToPointF();
            sepoints[1] = endPoint.ToPointF();
           // sepoints[2] = new PointF(width / 2, -height / 2);

            matrix2.TransformPoints(sepoints);

            Vector2F center = new Vector2F();
            center.X = width / 2;
            center.Y = -height / 2;
            Vector2F vect1 = new Vector2F(sepoints[0]) - center;
            Vector2F vect2 = new Vector2F(sepoints[1]) - center;
            double len1 = Math.Sqrt(vect1.X * vect1.X + vect1.Y * vect1.Y);
            double len2 = Math.Sqrt(vect2.X * vect2.X + vect2.Y * vect2.Y);
           
            
            double sins = vect1.Y / len1;
            double sine = vect2.Y/ len2;

            double angles = 0, anglee = 0;

            if (vect1.X >= 0 && vect1.Y >= 0)//第一象限
            {
                 angles = MathEx.RadiansToDegrees(Math.PI - Math.Asin(sins));
            }
            else if (vect1.X < 0 && vect1.Y >= 0)//第二象限
            {
                angles = MathEx.RadiansToDegrees(Math.Asin(sins));
            }
            else if (vect1.X > 0 && vect1.Y < 0)//第三象限
            {
                angles = -MathEx.RadiansToDegrees(Math.Asin(sins)) + 180;
            }
            else if (vect1.X < 0 && vect1.Y < 0)//第四象限
            {
                angles = 360 +MathEx.RadiansToDegrees(Math.Asin(sins));
            }


            if (vect2.X >= 0 && vect2.Y >= 0)
            {
                anglee = MathEx.RadiansToDegrees(Math.PI - Math.Asin(sine));
            }
            else if (vect2.X < 0 && vect2.Y >= 0)
            {
                anglee = MathEx.RadiansToDegrees(Math.Asin(sine));
            }
            else if (vect2.X > 0 && vect2.Y < 0)
            {
                anglee = -MathEx.RadiansToDegrees(Math.Asin(sine)) + 180;
            }
            else if (vect2.X < 0 && vect2.Y < 0)
            {
                anglee = 360+MathEx.RadiansToDegrees(Math.Asin(sine));
            }


            
            Matrix oldmatrix = graphics.Transform;
            graphics.Transform = matrix;
            Console.WriteLine(String.Format("angle1:{0},angle2:{1}",angles,anglee));
            //graphics.DrawArc(pen, new RectangleF(0, -height, width, height),(float)angles-45,(float)(anglee - angles));
            double dif = 0;
            if (direction)
            {
                if (anglee > angles)//起始角 < 结束角
                {
                    dif = anglee - angles;
                }
                else
                {
                    dif = 360 - angles +anglee;
                }
            }
            graphics.DrawArc(pen, new RectangleF(0, -height, width, height), 0, (float)dif);
          //  graphics.DrawArc(new Pen(Color.Red,2), new RectangleF(0, -height, width, height), 360 - (float)angles, (float)dif);
            GraphicsEx.DrawVertex(graphics, Pens.Aquamarine, new Vector2F(sepoints[0]));
            GraphicsEx.DrawVertex(graphics, Pens.Aquamarine, new Vector2F(sepoints[1]));

            #region
           
            GraphicsEx.DrawVertex(graphics, Pens.Black, new Vector2F(0, 0));
         //  GraphicsEx.DrawVertex(graphics, Pens.Tomato, new Vector2F(width / 2, -height / 2));
            GraphicsEx.DrawLine(graphics, Pens.Yellow, new Vector2F(0, 0), new Vector2F(0, 200));
            GraphicsEx.DrawLine(graphics, Pens.Green, new Vector2F(0, 0), new Vector2F(200, 0));
            #endregion
            //graphics.DrawArc(pen, new RectangleF(0, -height, width, height), 0, 270);
            graphics.Transform = oldmatrix;
            //GraphicsEx.DrawVertex(graphics, Pens.Violet, new Vector2F(sepoints[2]));
            
        }
    }
}
